from numbers import Number
from typing import List, Union, Literal, Dict

from modules.amis.component.base import SchemaNode, FlexJustify, FlexAlignItems, Action, BaseSchema, \
    Position, Direction, LineStyle, wrap, EmptySchema, OnEvent, TabsMode, LeftAndRight, Size, NumberAndStr, Renderable, \
    FormHorizontal, SchemaCollection, SchemaClassName
from modules.amis.component.datashow import Remark


class Page(BaseSchema):
    """
    Page 组件是 amis 页面 JSON 配置中顶级容器组件，是整个页面配置的入口组件。

    type        指定为 Page 组件

    title	    页面标题

    subTitle	页面副标题

    remark	    标题附近会出现一个提示图标，鼠标放上去会提示该内容。
    aside	往页面的边栏区域加内容
    asideResizor	页面的边栏区域宽度是否可调整
    asideMinWidth	页面边栏区域的最小宽度
    asideMaxWidth	页面边栏区域的最大宽度
    asideSticky	用来控制边栏固定与否
    toolbar	往页面的右上角加内容，需要注意的是，当有 title 时，该区域在右上角，没有时该区域在顶部
    body	往页面的内容区域加内容
    className	外层 dom 类名
    cssVars	自定义 CSS 变量，请参考样式
    toolbarClassName	Toolbar dom 类名
    bodyClassName	Body dom 类名
    asideClassName	Aside dom 类名
    headerClassName	Header 区域 dom 类名
    initApi	Page 用来获取初始数据的 api。返回的数据可以整个 page 级别使用。
    initFetch	是否起始拉取 initApi
    initFetchOn	是否起始拉取 initApi, 通过表达式配置
    interval	刷新时间(最小 1000)
    silentPolling	配置刷新时是否显示加载动画
    stopAutoRefreshWhen	通过表达式来配置停止刷新的条件
    pullRefresh	下拉刷新配置（仅用于移动端）
    """

    def __init__(self,
                 title: SchemaNode = None,
                 subTitle: SchemaNode = None,
                 body: SchemaNode = None,
                 remark: Remark = None,
                 aside: SchemaNode = None,
                 toolbar: SchemaNode = None,
                 className: str = None,
                 data: Dict = None,
                 onEvent: OnEvent = None,
                 **kwargs,
                 ):
        super().__init__()
        self.type: str = "page"
        self.title: SchemaNode = title
        self.subTitle: SchemaNode = subTitle
        self.body: SchemaNode = wrap(body)
        self.remark: Remark = remark
        self.aside: SchemaNode = aside
        self.toolbar: SchemaNode = toolbar
        self.className: str = className
        self.data: Dict = data
        self.onEvent: OnEvent = onEvent
        for key, value in kwargs.items():
            self.__dict__[key] = value


class Divider(BaseSchema):
    def __init__(self,
                 className: str = "",
                 lineStyle: LineStyle = LineStyle.none,
                 direction: Direction = Direction.none,
                 color: str = "",
                 rotate: float = 0,
                 title: SchemaNode = "",
                 titleClassName: str = "",
                 titlePosition: Position = "center",
                 **kwargs,
                 ):
        super().__init__()
        self.type: str = "divider"
        self.className: str = className
        self.lineStyle: LineStyle = lineStyle
        self.direction: Direction = direction
        self.color: str = color
        self.rotate: float = rotate
        self.title: SchemaNode = title
        self.titleClassName: str = titleClassName
        self.titlePosition: Position = titlePosition
        for key, value in kwargs.items():
            self.__dict__[key] = value


class Container(BaseSchema):
    def __init__(self,
                 body: SchemaNode = None,
                 className: str = "",
                 bodyClassName: str = "",
                 wrapperComponent: str = "div",
                 onEvent: OnEvent = None,
                 **kwargs,
                 ):
        super().__init__()
        self.type: str = "page"
        self.body: SchemaNode = wrap(body)
        self.className: str = className
        self.bodyClassName: str = bodyClassName
        self.wrapperComponent: str = wrapperComponent
        self.onEvent: OnEvent = onEvent
        for key, value in kwargs.items():
            self.__dict__[key] = value


class Flex(BaseSchema):
    """
    Flex 布局是基于 CSS Flex 实现的布局效果，它比 Grid 和 HBox 对子节点位置的可控性更强，比用 CSS 类的方式更易用，并且默认使用水平垂直居中的对齐。

    Args:
        type:	string	flex	指定为 Flex 渲染器
        className:	string		css 类名
        justify:	string		"start", "flex-start", "center", "end", "flex-end", "space-around", "space-between", "space-evenly"
        alignItems:	string		"stretch", "start", "flex-start", "flex-end", "end", "center", "baseline"
        style:	object		自定义样式
        items[]:	SchemaNode
    """
    def __init__(self,
                 items: SchemaNode = None,
                 className: str = "",
                 justify: FlexJustify = FlexJustify.none,
                 alignItems: FlexAlignItems = FlexAlignItems.none,
                 **kwargs,
                 ):
        super().__init__()
        self.type: str = "flex"
        self.items: SchemaNode = items
        self.className: str = className
        self.justify: FlexJustify = justify
        self.alignItems: FlexAlignItems = alignItems
        for key, value in kwargs.items():
            self.__dict__[key] = value


class Panel(BaseSchema):
    """
    Page 页面

    Page 组件是 amis 页面 JSON 配置中顶级容器组件，是整个页面配置的入口组件。

    Args:
        type:	string	"page"	指定为 Page 组件
        title:	SchemaNode		页面标题
        subTitle:	SchemaNode		页面副标题
        remark:	Remark		标题附近会出现一个提示图标，鼠标放上去会提示该内容。
        aside:	SchemaNode		往页面的边栏区域加内容
        asideResizor:	boolean		页面的边栏区域宽度是否可调整
        asideMinWidth:	number		页面边栏区域的最小宽度
        asideMaxWidth:	number		页面边栏区域的最大宽度
        asideSticky:	boolean	true	用来控制边栏固定与否
        toolbar:	SchemaNode		往页面的右上角加内容，需要注意的是，当有 title 时，该区域在右上角，没有时该区域在顶部
        body:	SchemaNode		往页面的内容区域加内容
        className:	string		外层 dom 类名
        cssVars:	object		自定义 CSS 变量，请参考样式
        toolbarClassName:	string	v-middle wrapper text-right bg-light b-b	Toolbar dom 类名
        bodyClassName:	string	wrapper	Body dom 类名
        asideClassName:	string	w page-aside-region bg-auto	Aside dom 类名
        headerClassName:	string	bg-light b-b wrapper	Header 区域 dom 类名
        initApi:	API		Page 用来获取初始数据的 api。返回的数据可以整个 page 级别使用。
        initFetch:	boolean	true	是否起始拉取 initApi
        initFetchOn:	表达式		是否起始拉取 initApi, 通过表达式配置
        interval:	number	3000	刷新时间(最小 1000)
        silentPolling:	boolean	false	配置刷新时是否显示加载动画
        stopAutoRefreshWhen:	表达式	""	通过表达式来配置停止刷新的条件
        pullRefresh:	object	{disabled: true}	下拉刷新配置（仅用于移动端）
    """
    def __init__(self,
                 className: str = "",
                 title: SchemaNode = None,
                 header: SchemaNode = None,
                 body: SchemaNode = None,
                 footer: SchemaNode = None,
                 headerClassName: str = "",
                 footerClassName: str = "",
                 actionsClassName: str = "",
                 bodyClassName: str = "",
                 affixFooter: bool = False,
                 justify: FlexJustify = FlexJustify.none,
                 alignItems: FlexAlignItems = FlexAlignItems.none,
                 actions: List[Action] = None,
                 **kwargs,
                 ):
        super().__init__()
        self.type: str = "panel"
        self.title: SchemaNode = title
        self.header: SchemaNode = header
        self.body: SchemaNode = body
        self.footer: SchemaNode = footer
        self.affixFooter: bool = affixFooter
        self.className: str = className
        self.headerClassName: str = headerClassName
        self.footerClassName: str = footerClassName
        self.actionsClassName: str = actionsClassName
        self.bodyClassName: str = bodyClassName
        self.justify: FlexJustify = justify
        self.alignItems: FlexAlignItems = alignItems
        self.actions: List[Action] = actions
        for key, value in kwargs.items():
            self.__dict__[key] = value


class Collapse(BaseSchema):
    """
    Collapse 折叠器

    Args:
        type:	string	"collapse"	指定为 collapse 渲染器
        disabled:	boolean	false	禁用
        collapsed:	boolean	true	初始状态是否折叠
        key:	string | number	-	标识
        header:	string | SchemaNode	-	标题
        body:	string | SchemaNode	-	内容
        showArrow:	boolean	true	是否展示图标
    """
    def __init__(self,
                 disabled: bool = False,
                 collapsed: bool = True,
                 key: str = "",
                 header: SchemaNode = None,
                 body: SchemaNode = None,
                 showArrow: bool = True,
                 id: str = "",
                 onEvent: OnEvent = None,
                 **kwargs,
                 ):
        super().__init__()
        self.type = "collapse"
        self.id: str = id
        self.disabled: bool = disabled
        self.collapsed: bool = collapsed
        self.key: str = key
        self.header: SchemaNode = header
        self.body: SchemaNode = body
        self.showArrow: bool = showArrow
        self.onEvent: OnEvent = onEvent
        for key, value in kwargs.items():
            self.__dict__[key] = value


class CollapseGroup(BaseSchema):
    """
    CollapseGroup 折叠器

    Args:
        type:	string	"collapse-group"	指定为 collapse-group 渲染器
        activeKey:	Array<string | number | never> | string | number	-	初始化激活面板的 key
        accordion:	boolean	false	手风琴模式
        expandIcon:	SchemaNode	-	自定义切换图标
        expandIconPosition:	string	"left"	设置图标位置，可选值left | right
        enableFieldSetStyle:	boolean	true	当Collapse作为Form组件的子元素时，开启该属性后组件样式设置为FieldSet组件的样式，默认开启
    """
    def __init__(self,
                 activeKey: Union[List, str] = None,
                 accordion: bool = False,
                 expandIcon: SchemaNode = None,
                 expandIconPosition: LeftAndRight = LeftAndRight.left,
                 enableFieldSetStyle: bool = True,
                 onEvent: OnEvent = None,
                 body: List[Collapse] = None,
                 **kwargs,
                 ):
        super().__init__()
        self.type = "collapse-group"
        self.activeKey: Union[List, str] = activeKey
        self.accordion: bool = accordion
        self.expandIcon: SchemaNode = expandIcon
        self.expandIconPosition: LeftAndRight = expandIconPosition
        self.enableFieldSetStyle: bool = enableFieldSetStyle
        self.onEvent: OnEvent = onEvent
        self.body: List[Collapse] = body
        for key, value in kwargs.items():
            self.__dict__[key] = value


class TabItem(BaseSchema):
    """

    Args:
        title:	string | SchemaNode		Tab 标题，当是 SchemaNode 时，该 title 不支持 editable 为 true 的双击编辑
        icon:	icon		Tab 的图标
        iconPosition:	left / right	left	Tab 的图标位置
        tab:	SchemaNode		内容区
        hash:	string		设置以后将跟 url 的 hash 对应
        reload:	boolean		设置以后内容每次都会重新渲染，对于 crud 的重新拉取很有用
        unmountOnExit:	boolean		每次退出都会销毁当前 tab 栏内容
        className:	string	"bg-white b-l b-r b-b wrapper-md"	Tab 区域样式
        tip:	string		3.2.0及以上版本支持 Tab 提示，当开启 showTip 时生效，作为 Tab 在 hover 时的提示显示，可不配置，如不设置，tabs[x].title 作为提示显示
        closable:	boolean	false	是否支持删除，优先级高于组件的 closable
        disabled:	boolean	false	是否禁用
    """
    def __init__(self,
                 title: SchemaNode = "",
                 icon: str = "",
                 iconPosition: LeftAndRight = LeftAndRight.left,
                 tab: SchemaNode = None,
                 hash: str = "",
                 reload: bool = False,
                 unmountOnExit: bool = False,
                 className: str = "",
                 tip: str = "",
                 closable: bool = False,
                 disabled: bool = False,
                 **kwargs,
                 ):
        super().__init__()
        self.title: SchemaNode = title
        self.icon: str = icon
        self.iconPosition: LeftAndRight = iconPosition
        self.tab: SchemaNode = tab
        self.hash: str = hash
        self.reload: bool = reload
        self.unmountOnExit: bool = unmountOnExit
        self.className: str = className
        self.tip: str = tip
        self.closable: bool = closable
        self.disabled: bool = disabled
        for key, value in kwargs.items():
            self.__dict__[key] = value


class Tabs(BaseSchema):
    """
    Tabs 选项卡

    Args:
        type:	string	"tabs"	指定为 Tabs 渲染器
        defaultKey:	string / number		组件初始化时激活的选项卡，hash 值或索引值，支持使用表达式 2.7.1 以上版本
        activeKey:	string / number		激活的选项卡，hash 值或索引值，支持使用表达式，可响应上下文数据变化
        className:	string		外层 Dom 的类名
        linksClassName:	string		Tabs 标题区的类名
        contentClassName:	string		Tabs 内容区的类名
        tabsMode:	string		展示模式，取值可以是 line、card、radio、vertical、chrome、simple、strong、tiled、sidebar
        tabs:	Array		tabs 内容
        source:	string		tabs 关联数据，关联后可以重复生成选项卡
        toolbar:	SchemaNode		tabs 中的工具栏
        toolbarClassName:	string		tabs 中工具栏的类名
        tabs[x].title:	string | SchemaNode		Tab 标题，当是 SchemaNode 时，该 title 不支持 editable 为 true 的双击编辑
        tabs[x].icon:	icon		Tab 的图标
        tabs[x].iconPosition:	left / right	left	Tab 的图标位置
        tabs[x].tab:	SchemaNode		内容区
        tabs[x].hash:	string		设置以后将跟 url 的 hash 对应
        tabs[x].reload:	boolean		设置以后内容每次都会重新渲染，对于 crud 的重新拉取很有用
        tabs[x].unmountOnExit:	boolean		每次退出都会销毁当前 tab 栏内容
        tabs[x].className:	string	"bg-white b-l b-r b-b wrapper-md"	Tab 区域样式
        tabs[x].tip	string:		3.2.0及以上版本支持 Tab 提示，当开启 showTip 时生效，作为 Tab 在 hover 时的提示显示，可不配置，如不设置，tabs[x].title 作为提示显示
        tabs[x].closable:	boolean	false	是否支持删除，优先级高于组件的 closable
        tabs[x].disabled:	boolean	false	是否禁用
        mountOnEnter:	boolean	true	只有在点中 tab 的时候才渲染
        unmountOnExit:	boolean	false	切换 tab 的时候销毁
        addable:	boolean	false	是否支持新增
        addBtnText:	string	增加	新增按钮文案
        closable:	boolean	false	是否支持删除
        draggable:	boolean	false	是否支持拖拽
        showTip:	boolean	false	是否支持提示
        showTipClassName:	string	'' 	提示的类
        editable:	boolean	false	是否可编辑标签名。当 tabs[x].title 为 SchemaNode 时，双击编辑 Tab 的 title 显示空的内容
        scrollable:	boolean	true	是否导航支持内容溢出滚动。（属性废弃）
        sidePosition:	left / right	left	sidebar 模式下，标签栏位置
        collapseOnExceed:	number		当 tabs 超出多少个时开始折叠
        collapseBtnLabel:	string	more	用来设置折叠按钮的文字
        swipeable:	boolean	false	是否开启手势滑动切换（移动端生效）
    """
    def __init__(self,
                 defaultKey: Union[List, str] = None,
                 activeKey: Union[List, str] = None,
                 tabs: List[TabItem] = None,
                 className: str = "",
                 linksClassName: str = "",
                 contentClassName: str = "",
                 tabsMode: TabsMode = TabsMode.none,
                 source: str = "",
                 toolbar: SchemaNode = None,
                 toolbarClassName: str = "",
                 mountOnEnter: bool = True,
                 unmountOnExit: bool = False,
                 addable: bool = False,
                 addBtnText: str = "",
                 closable: bool = False,
                 draggable: bool = False,
                 showTip: bool = False,
                 showTipClassName: str = "",
                 editable: bool = False,
                 sidePosition: LeftAndRight = "left",
                 collapseOnExceed: Number = None,
                 collapseBtnLabel: str = "more",
                 swipeable: bool = True,
                 onEvent: OnEvent = None,
                 **kwargs,
                 ):
        super().__init__()
        self.type = "tabs"
        self.defaultKey: Union[List, str] = defaultKey
        self.activeKey: Union[List, str] = activeKey
        self.tabs: List[TabItem] = tabs
        self.className: str = className
        self.linksClassName: str = linksClassName
        self.contentClassName: str = contentClassName
        self.tabsMode: TabsMode = tabsMode
        self.source: str = source
        self.toolbar: SchemaNode = toolbar
        self.toolbarClassName: str = toolbarClassName
        self.mountOnEnter: bool = mountOnEnter
        self.unmountOnExit: bool = unmountOnExit
        self.addable: bool = addable
        self.addBtnText: str = addBtnText
        self.closable: bool = closable
        self.draggable: bool = draggable
        self.showTip: bool = showTip
        self.showTipClassName: str = showTipClassName
        self.editable: bool = editable
        self.sidePosition: LeftAndRight = sidePosition
        self.collapseOnExceed: Number = collapseOnExceed
        self.collapseBtnLabel: str = collapseBtnLabel
        self.swipeable: bool = swipeable
        self.onEvent: OnEvent = onEvent
        for key, value in kwargs.items():
            self.__dict__[key] = value


class Wrapper(BaseSchema):
    """
    Wrapper 包裹容器

    简单的一个包裹容器组件，相当于用 div 包含起来，最大的用处是用来配合 css 进行布局。

    Args:
        type:	string	"wrapper"	指定为 Wrapper 渲染器
        className:	string		外层 Dom 的类名
        size:	string		支持: xs、sm、md和lg
        style:	Object | string		自定义样式
        body:	SchemaNode		内容容器
    """

    def __init__(self,
                 body: SchemaNode = None,
                 className: str = "",
                 size: Size = Size.none,
                 style: Union[str, Dict] = "",
                 **kwargs,
                 ):
        super().__init__()
        self.type: str = "wrapper"
        self.body: SchemaNode = body
        self.className: str = className
        self.size: Size = size
        self.style: Union[str, Dict] = style
        for key, value in kwargs.items():
            self.__dict__[key] = value


class Pagination(BaseSchema):
    """
    Pagination 分页组件

    Args:
        type:	string	"pagination"	指定为 Pagination 渲染器
        mode:	normal | simple	normal	迷你版本/简易版本 只显示左右箭头，配合 hasNext 使用
        layout:	string | string[]	["pager"]	通过控制 layout 属性的顺序，调整分页结构布局
        maxButtons:	number | string	5	最多显示多少个分页按钮，最小为 5
        total:	number | string		总条数
        activePage:	number | string	1	当前页数
        perPage:	number | string	10	每页显示多条数据
        showPerPage:	boolean	false	是否展示 perPage 切换器 layout 和 showPerPage 都可以控制
        size:	'sm' | 'md'	md	组件尺寸，支持md、sm设置	6.0.0后支持变量
        ellipsisPageGap:	number | string	5	多页跳转页数，页数较多出现...时点击省略号时每次前进/后退的页数，默认为5	6.0.0后支持变量
        perPageAvailable:	number[]	[10, 20, 50, 100]	指定每页可以显示多少条
        showPageInput:	boolean	false	是否显示快速跳转输入框 layout 和 showPageInput 都可以控制
        disabled:	boolean	false	是否禁用
        onPageChange:	page、perPage 改变时会触发	(page: number, perPage: number) => void;	分页改变触发
    """

    def __init__(self,
                 body: SchemaNode = None,
                 mode: Literal["normal", "simple"] = "normal",
                 layout: Literal["normal", "simple"] = "pager",
                 maxButtons: NumberAndStr = 5,
                 total: NumberAndStr = 0,
                 activePage: NumberAndStr = 1,
                 perPage: NumberAndStr = 10,
                 showPerPage: bool = False,
                 size: Size = Size.none,
                 ellipsisPageGap: NumberAndStr = 5,
                 perPageAvailable: List[Number] = None,
                 showPageInput: bool = False,
                 disabled: bool = False,
                 onEvent: OnEvent = None,
                 **kwargs,
                 ):
        super().__init__()
        self.type: str = "pagination"
        self.body: SchemaNode = body
        self.mode: Literal["normal", "simple"] = mode
        self.layout: Literal["normal", "simple"] = layout
        self.maxButtons: NumberAndStr = maxButtons
        self.total: NumberAndStr = total
        self.activePage: NumberAndStr = activePage
        self.perPage: NumberAndStr = perPage
        self.showPerPage: bool = showPerPage
        self.size: Size = size
        self.ellipsisPageGap: NumberAndStr = ellipsisPageGap
        self.perPageAvailable: List[Number] = perPageAvailable
        self.showPageInput: bool = showPageInput
        self.disabled: bool = disabled
        self.onEvent: OnEvent = onEvent
        for key, value in kwargs.items():
            self.__dict__[key] = value


class GridColumn(Renderable):
    def __init__(
            self,
            xs: Union[Number, Literal['auto']] = None,
            sm: Union[Number, Literal['auto']] = None,
            md: Union[Number, Literal['auto']] = None,
            lg: Union[Number, Literal['auto']] = None,
            valign: Literal['top', 'middle', 'bottom', 'between'] = None,
            mode: Literal['normal', 'inline', 'horizontal'] = None,
            horizontal: FormHorizontal = None,
            body: SchemaCollection = None,
            columnClassName: SchemaClassName = None,
            style: any = None,
            **kwargs,
    ):
        super().__init__()
        # 极小屏（<768px）时宽度占比
        self.xs: Union[Number, Literal['auto']] = xs
        # 小屏时（>=768px）宽度占比
        self.sm: Union[Number, Literal['auto']] = sm
        # 中屏时(>=992px)宽度占比
        self.md: Union[Number, Literal['auto']] = md
        # 大屏时(>=1200px)宽度占比
        self.lg: Union[Number, Literal['auto']] = lg
        # 垂直对齐方式
        self.valign: Literal['top', 'middle', 'bottom', 'between'] = valign
        # 配置子表单项默认的展示方式。
        self.mode: Literal['normal', 'inline', 'horizontal'] = mode
        # 如果是水平排版，这个属性可以细化水平排版的左右宽度占比。
        self.horizontal: FormHorizontal = horizontal
        #
        self.body: SchemaCollection = body
        # 列类名
        self.columnClassName: SchemaClassName = columnClassName
        # 样式
        self.style: any = style

        for key, value in kwargs.items():
            self.__dict__[key] = value


class Grid(BaseSchema):
    """
    Grid 格子布局渲染器。
    """
    def __init__(self,
                 columns: List[GridColumn] = None,
                 className: str = None,
                 valign: Literal['top', 'middle', 'bottom', 'between'] = None,
                 align: Literal['left', 'right', 'between', 'center'] = None,
                 gap: Literal['xs', 'sm', 'base', 'none', 'md', 'lg'] = None,
                 **kwargs,
                 ):
        super().__init__()
        self.type: str = "grid"
        # 列集合
        self.columns: List[GridColumn] = columns
        # 垂直对齐方式
        self.valign: Literal['top', 'middle', 'bottom', 'between'] = valign
        # 水平对齐方式
        self.align: Literal['left', 'right', 'between', 'center'] = align
        # 水平间距
        self.gap: Literal['xs', 'sm', 'base', 'none', 'md', 'lg'] = gap
        # 外层 Dom 的类名
        self.className: str = className

        for key, value in kwargs.items():
            self.__dict__[key] = value